'use client'; // D2 종목 글쓰기 폼 — 제목/본문 + 선택적 예측(방향·기간·목표가). // POST /api/boards/stock/posts (프록시 경유, JWT). 성공 시 라우터 새로고침으로 목록 갱신. import '@/app/styles/community.scss'; import { useState } from 'react'; import { useRouter } from 'next/navigation'; import { fetchApi } from '@/lib/utils/client'; import { CreateStockPostRequest, CreateStockPostResponse, PredictionDirection, PredictionHorizon, PredictionDirectionValue, PredictionHorizonValue } from '@/types/community'; interface Props { stockCode: string; stockName?: string|null; onDone?: () => void; } export default function StockWriteForm({ stockCode, stockName, onDone }: Props) { const router = useRouter(); const [subject, setSubject] = useState(''); const [content, setContent] = useState(''); const [withPrediction, setWithPrediction] = useState(false); const [direction, setDirection] = useState(PredictionDirection.Up); const [horizon, setHorizon] = useState(PredictionHorizon.Short); const [targetPrice, setTargetPrice] = useState(''); const [submitting, setSubmitting] = useState(false); const [error, setError] = useState(null); async function handleSubmit(e: React.FormEvent) { e.preventDefault(); setError(null); if (!subject.trim()) { setError('제목을 입력해주세요.'); return; } const body: CreateStockPostRequest = { stockCode, subject: subject.trim(), content }; if (withPrediction) { const parsedTarget = targetPrice.trim() ? Number(targetPrice.replace(/,/g, '')) : null; if (parsedTarget !== null && (Number.isNaN(parsedTarget) || parsedTarget <= 0)) { setError('목표가는 0보다 큰 숫자여야 합니다.'); return; } body.prediction = { direction, horizonDays: horizon, targetPrice: parsedTarget }; } setSubmitting(true); try { const res = await fetchApi('/api/boards/stock/posts', { method: 'POST', body, silent: true }); if (!res.success) { setError(res.message || (res.errors && res.errors[0]?.description) || '글 등록에 실패했습니다.'); setSubmitting(false); return; } setSubject(''); setContent(''); setWithPrediction(false); setTargetPrice(''); onDone?.(); router.refresh(); } catch (err) { setError(err instanceof Error ? err.message : '글 등록에 실패했습니다.'); } finally { setSubmitting(false); } } return (
{stockName ? `${stockName}(${stockCode})` : stockCode} 토론 글쓰기
setSubject(e.target.value)} maxLength={200} placeholder='제목을 입력하세요' />
{withPrediction && (
setTargetPrice(e.target.value)} placeholder='예: 75000' />
)}

예측 기준가는 작성 시점 최신 종가(T+1)로 스냅샷되며, 삭제해도 채점 기록은 유지됩니다.

{error &&

{error}

}
); }